﻿using DevExpress.Data.Filtering;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using Inaction.Mapping;
using Inaction.UI.Extensions.ControlExtensions.Grid;
using System.Reflection;
using System.Windows.Forms;
using System.Linq;
using System.Drawing;
using Inaction.UI.Common;
using DevExpress.Utils.Menu;
using System;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraEditors.Controls;
using Inaction.Message;

namespace Inaction.UI.Extensions.ControlExtensions
{
    internal class GridExtender
    {
        public static void Extend(Control c, Form form)
        {
            if (!(c is GridControl)) return;
            var grid = c as GridControl;
            if (grid.UseEmbeddedNavigator != true)
            {
                grid.UseEmbeddedNavigator = true;
                grid.EmbeddedNavigator.Buttons.Append.Visible = false;
                grid.EmbeddedNavigator.Buttons.CancelEdit.Visible = false;
                grid.EmbeddedNavigator.Buttons.EnabledAutoRepeat = false;
                grid.EmbeddedNavigator.Buttons.EndEdit.Visible = false;
                grid.EmbeddedNavigator.Buttons.Remove.Visible = false;
            }
            new GridExtender(grid, form);           
        }

        #region 变量/属性
        BarManager barManager;
        GridControl grid;
        ClassInfo classInfo;
        BindingSource bindingSource;
        #endregion

        #region 构造
        private GridExtender(GridControl grid, Form form)
        {
            this.grid = grid;
            barManager = BarManager.GetBarManager(form);
            bindingSource = grid.DataSource as BindingSource;
            if (bindingSource != null)
            {
                var entityType = BindingHelper.GetListItemType(bindingSource);
                if (entityType == null || entityType.GetInterface(typeof(Inaction.Business.IEntity).FullName) == null) return;
                classInfo = ClassInfo.LoadInfo(entityType);
            }
           
            foreach (BaseView view in grid.Views)
            { 
                #region ColumnView
                if (view is ColumnView)
                {
                    var gridView = view as ColumnView;
                    gridView.InvalidRowException += (g, t) => { MessageHost.ShowMessage(t.ErrorText); };
                    gridView.InvalidValueException += (g1, t1) => { MessageHost.ShowMessage(t1.ErrorText); };
                    gridView.ShowingEditor += gridView_ShowingEditor;
                    gridView.CellValueChanged += gridView_CellValueChanged;
                    gridView.GotFocus += (sender, e) =>
                    {
                        if (gridView.VisibleColumns.Count > 0)
                        {
                            gridView.FocusedColumn = gridView.VisibleColumns[0];
                        }
                    };
                    for (int i = 0; i < gridView.Columns.Count; i++)
                    {
                        var column = gridView.Columns[i];

                        if (column.ColumnEdit != null)
                        {
                            if (column.ColumnEdit is RepositoryItemGridLookUpEdit)
                            {
                                var gLue = column.ColumnEdit as RepositoryItemGridLookUpEdit;
                                gLue.Popup += (sender, e) =>
                                {
                                    form.BeginInvoke(new System.Windows.Forms.MethodInvoker(delegate
                                    {
                                        FilterLookup(sender);
                                    }));
                                };
                                gLue.EditValueChanging += (sender1, e1) =>
                                {
                                    form.BeginInvoke(new System.Windows.Forms.MethodInvoker(delegate
                                    {
                                        FilterLookup(sender1);
                                    }));
                                };
                            }
                            if (column.ColumnEdit is RepositoryItemLookUpEdit)
                            {
                                var lue = column.ColumnEdit as RepositoryItemLookUpEdit;
                                if (lue.DataSource == null && classInfo != null)
                                {
                                    var property = classInfo.NameProperties[column.FieldName];
                                    if (property.UnderlyingType.IsEnum || property.UnderlyingType == typeof(bool))
                                    {
                                        var pType = property.UnderlyingType;
                                        if (pType == typeof(Boolean))
                                        {
                                            pType = typeof(Rule.BooleanEnum);
                                        }
                                        var source = Rule.EnumDescriptionList.Query(pType);
                                        if (source != null)
                                        {
                                            lue.DataSource = source;
                                            lue.DisplayMember = "Description";
                                            lue.ValueMember = "Value";
                                            lue.Columns.Clear();
                                            lue.Columns.Add(new LookUpColumnInfo("Key", "键"));
                                            lue.Columns.Add(new LookUpColumnInfo("Description", "说明"));
                                        }
                                    }
                                }
                            }


                        }
                        if (classInfo != null)
                        {
                            if (classInfo.NameProperties.ContainsKey(column.FieldName))
                            {
                                var p = classInfo.NameProperties[column.FieldName];
                                if (p.Required != null)
                                {
                                    column.AppearanceHeader.ForeColor = Color.Blue;
                                }
                                if (p.PropertyInfo.GetSetMethod() == null)
                                {
                                    column.OptionsColumn.ReadOnly = true;
                                }
                            }
                            else
                            {
                                var propertyInfo = classInfo.EntityType.GetProperty(column.FieldName);
                                if (propertyInfo != null && propertyInfo.GetSetMethod() == null)
                                {
                                    column.OptionsColumn.ReadOnly = true;
                                }
                            }
                        }
                    }
                }
                #endregion

                if (view is GridView)
                {
                    var gridView = view as GridView;
                    gridView.OptionsNavigation.EnterMoveNextColumn = true;
                    gridView.ValidateRow += gridView_ValidateRow;
                    ChangeCaptionHelper.Extend(gridView);
                    FooterHelper.Extend(gridView);
                    new GridExportHelper(gridView);
                }
            }
            GridRowBatchSetHelper.Extend(grid);
        }

        void gridView_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
        {
            if (e.HitInfo.Column == null) return;
            var view = sender as GridView;
            if (view == null) return;
            var extendMenuItem = e.Menu.Items.Cast<DXMenuItem>().FirstOrDefault(p => p.Caption == "扩展");
            if (extendMenuItem == null)
            {
                extendMenuItem = new DXSubMenuItem("扩展");
                extendMenuItem.Image = Properties.Resources.Modify;
                extendMenuItem.Tag = e.HitInfo.Column;
                extendMenuItem.BeginGroup = true;
                e.Menu.Items.Insert(0, extendMenuItem);
                extendMenuItem.Tag = e.HitInfo.Column;
            }
            extendMenuItem.Visible = e.HitInfo.InColumn;
        }
        #endregion

        #region 事件
        void gridView_CellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            var gridView = sender as ColumnView;
            var error = gridView.GetColumnError(e.Column);
            barManager.ShowMessage(error);
        }

        void gridView_ShowingEditor(object sender, System.ComponentModel.CancelEventArgs e)
        {
            var gridView = sender as ColumnView;
            if (gridView.OptionsBehavior.ReadOnly == true
                || gridView.OptionsBehavior.Editable == false
                || gridView.FocusedColumn.ReadOnly == true
                || gridView.FocusedColumn.OptionsColumn.AllowEdit == false) return;
            var entity = gridView.GetRow(gridView.FocusedRowHandle) as Inaction.Business.IEntity;
            e.Cancel = !entity.CanSetProperty(gridView.FocusedColumn.FieldName);
            if (e.Cancel == true)
            {
                if (gridView.FocusedColumn.VisibleIndex == gridView.VisibleColumns.Count - 1) return;
                gridView.FocusedColumn = gridView.VisibleColumns[gridView.FocusedColumn.VisibleIndex + 1];
            }
        }

        void gridView_ValidateRow(object sender, ValidateRowEventArgs e)
        {
            e.ErrorText = string.Empty;
        }
        #endregion

        #region 方法
        void ShowErrorMessage(ColumnView view, string error)
        {
            var barManager = BarManager.GetBarManager(view.GridControl.FindForm());
            if (barManager != null)
            {
                barManager.ShowMessage(error);
            }
            else
            {
                MessageHost.ShowMessage(error);
            }
        }

        void FilterLookup(object sender)
        {
            var glue = sender as GridLookUpEdit;
            var gridView = glue.Properties.View as GridView;
            gridView.ClearColumnsFilter();
            var firstFieldName = glue.Properties.View.VisibleColumns[0].FieldName;
            FieldInfo fi = gridView.GetType().GetField("extraFilter", BindingFlags.NonPublic | BindingFlags.Instance);
            BinaryOperator op = new BinaryOperator(firstFieldName, glue.AutoSearchText + "%", BinaryOperatorType.Like);
            string filterCondition = new GroupOperator(op).ToString();
            fi.SetValue(gridView, filterCondition);
            MethodInfo method = gridView.GetType().GetMethod("ApplyColumnsFilterEx", BindingFlags.NonPublic | BindingFlags.Instance);
            method.Invoke(gridView, null);
        }
        #endregion
    }
}